/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.client.tree.view;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.TransferHandler;

/**
 *
 * @author WalterL
 */
public class DndButton extends JButton implements MouseMotionListener, MouseListener {
    private MouseEvent firstMouseEvent = null;
    static boolean installInputMapBindings = true;
    private String type;
    
    class  ButtonTransferHandler extends TransferHandler {
        DataFlavor buttonFlavor = DataFlavor.stringFlavor;
        boolean shouldRemove;
        
        public boolean importData(JComponent c, Transferable t) {
            return false;
        }
        
        protected Transferable createTransferable(JComponent c) {
            return new StringSelection(((DndButton)c).getType());
        }
        
        public int getSourceActions(JComponent c) {
            return COPY;
        }
        
        public boolean canImport(JComponent c, DataFlavor[] flavors) {
            return false;
        }
        
    }
    
    /** Creates a new instance of DndButton
     * @param type 
     */
    public DndButton(String type) {
        this.type = type;
        setTransferHandler(new ButtonTransferHandler());
        addMouseMotionListener(this);
        addMouseListener(this);
        
        //Add the cut/copy/paste key bindings to the input map.
        //Note that this step is redundant if you are installing
        //menu accelerators that cause these actions to be invoked.
        //DragPictureDemo does not use menu accelerators and, since
        //the default value of installInputMapBindings is true,
        //the bindings are installed.  DragPictureDemo2 does use
        //menu accelerators and so calls setInstallInputMapBindings
        //with a value of false.  Your program would do one or the
        //other, but not both.
        if (installInputMapBindings) {
            InputMap imap = this.getInputMap();
            imap.put(KeyStroke.getKeyStroke("ctrl X"),
                    TransferHandler.getCutAction().getValue(Action.NAME));
            imap.put(KeyStroke.getKeyStroke("ctrl C"),
                    TransferHandler.getCopyAction().getValue(Action.NAME));
            imap.put(KeyStroke.getKeyStroke("ctrl V"),
                    TransferHandler.getPasteAction().getValue(Action.NAME));
        }
        
        //Add the cut/copy/paste actions to the action map.
        //This step is necessary because the menu's action listener
        //looks for these actions to fire.
        ActionMap map = this.getActionMap();
        map.put(TransferHandler.getCutAction().getValue(Action.NAME),
                TransferHandler.getCutAction());
        map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
                TransferHandler.getCopyAction());
        map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
                TransferHandler.getPasteAction());
    }
    
    public void mousePressed(MouseEvent e) {
        firstMouseEvent = e;
        e.consume();
    }
    
    public void mouseDragged(MouseEvent e) {
        //Don't bother to drag if the component displays no image.
        if (firstMouseEvent != null) {
            e.consume();
            
            int dx = Math.abs(e.getX() - firstMouseEvent.getX());
            int dy = Math.abs(e.getY() - firstMouseEvent.getY());
            //Arbitrarily define a 5-pixel shift as the
            //official beginning of a drag.
            if (dx > 5 || dy > 5) {
                //This is a drag, not a click.
                JComponent c = (JComponent)e.getSource();
                TransferHandler handler = c.getTransferHandler();
                //Tell the transfer handler to initiate the drag.
                handler.exportAsDrag(c, firstMouseEvent, TransferHandler.COPY);
                firstMouseEvent = null;
            }
        }
    }
    
    public void mouseReleased(MouseEvent e) {
        firstMouseEvent = null;
    }
    
    public void mouseMoved(MouseEvent e) { }
    public void mouseExited(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseClicked(MouseEvent e) {}
    
    //This method is necessary because DragPictureDemo and
    //DragPictureDemo2 both use this class and DragPictureDemo
    //needs to have the input map bindings installed for
    //cut/copy/paste.  DragPictureDemo2 uses menu accelerators
    //and does not need to have the input map bindings installed.
    //Your program would use one approach or the other, but not
    //both.  The default for installInputMapBindings is true.
    public static void setInstallInputMapBindings(boolean flag) {
        installInputMapBindings = flag;
    }
    
    public static boolean getInstallInputMapBindingds() { //for completeness
        return installInputMapBindings;
    }

    public String getType() {
        return type;
    }
    
}
